import { get as getVal, writable, type Writable } from "svelte/store";
import { object, string, number, array, mixed } from "yup";
import type { JSONArray, JSONObject } from "@lib/json";
import { paramPrimitiveTypes, type ParamDataType } from "@lib/util/http";
import { JSONObjectSchema, JSONObjectSchemaOptional } from "@lib/json/yup";
import type { ObjectInstance } from "@component/type";

export type AppMock = {
  id: number;
  app_id: string;
  api_id: number;
  name: string;
  desc?: string;
  path_args?: JSONArray;
  query_args?: JSONArray;
  head_args?: JSONArray;
  body_args?: JSONObject;
  returned_example: JSONObject;
};

export const defaults = () => {
  return {
    id: undefined,
    app_id: null,
    api_id: 0,
    name: "new mock",
    returned_example: {},
  };
};

export type CreateAppMockResponse = {
  created: AppMock;
  mocks: AppMock[];
};

export type UpdateAppMockResponse = {
  updated: AppMock;
  mocks: AppMock[];
};

export type DeleteAppMockResponse = {
  deleted: AppMock;
  mocks: AppMock[];
};

export type RequestArgument = ObjectInstance & {
  datatype: ParamDataType;
};

export type AppMockPathArgument = RequestArgument;

export type AppMockUrlArgument = RequestArgument;

export type AppMockHeadArgument = RequestArgument;

export const makeDefault = (): RequestArgument => ({
  key: "",
  datatype: "string",
  val: "",
});

const RequestArgumentSchema = object({
  key: string().required("参数key必填"),
  datatype: mixed().oneOf(paramPrimitiveTypes as unknown as any[]),
  val: mixed().required("实参必须填写"),
});

export const AppMockSchema = object({
  id: number().required("api id必填"),
  app_id: string().required("app_id必填"),
  api_id: number().required("接口id必填"),
  name: string().required("名称必填"),
  desc: string().optional().nullable(),
  path_args: array().of(RequestArgumentSchema).nullable(),
  query_args: array().of(RequestArgumentSchema).nullable(),
  head_args: array().of(RequestArgumentSchema).nullable(),
  body_args: JSONObjectSchemaOptional,
  returned_example: JSONObjectSchema,
});

export const CreateAppMockSchema = AppMockSchema.omit([
  "id",
  "app_id",
  "api_id",
  "body_args",
]);
export const UpdateAppMockSchema = AppMockSchema.omit(["body_args"]);

type AppMockMap = {
  [k: string]: Writable<AppMock[]>;
};

const appMocksMap: AppMockMap = {};

export const setAppMockSubscribe = (app_id: string, o: AppMock[]) => {
  if (!appMocksMap[app_id]) {
    appMocksMap[app_id] = writable(o);
  }
  appMocksMap[app_id].set(o);
};

export const getAppMockSubscribe = (app_id: string) => {
  let v = appMocksMap[app_id];
  if (!v) {
    appMocksMap[app_id] = v = writable();
  }
  return v;
};

export const hasAppMockSubscribe = (app_id: string) => {
  return !!appMocksMap[app_id];
};

export default AppMock;